#include <QtGui/QtGui>

#include "include/mainwindow.h"

MainWindow::MainWindow()
{
    setMinimumSize (200, 150);
    resize(800, 600);

    QFont font("Monospace");
    font.setStyleHint(QFont::TypeWriter);

    brush = new QBrush;

    // Настройка центральной части
    treeWidget = new QTreeWidget;
    treeWidget->setColumnCount(1);
    treeWidget->setHeaderLabel("Name");
    treeWidget->setFont(font);

    textEdit = new QTextEdit;
    textEdit->setFont(font);

    tableWidgetVar = new QTableWidget;
    tableWidgetVar->setColumnCount(2);
    QStringList list;
    list << "Name" << "Content";
    tableWidgetVar->setHorizontalHeaderLabels(list);
    tableWidgetVar->setFont(font);

    tableWidgetTarget = new QTableWidget;
    tableWidgetTarget->setColumnCount(2);
    tableWidgetTarget->setHorizontalHeaderLabels(list);
    tableWidgetTarget->setFont(font);

    tabWidget = new QTabWidget;
    tabWidget->addTab(textEdit, tr("Sourse Text"));
    tabWidget->addTab(treeWidget, tr("Tree"));
    tabWidget->addTab(tableWidgetVar, tr("Variables"));
    tabWidget->addTab(tableWidgetTarget, tr("Special Targets"));
    setCentralWidget(tabWidget);

	// Widget for function - find
    findWidget = new FindWidget();
	
    // Настройка периферии
    createActions();
    createMenus();
    createToolBars();
    createStatusBar();

    connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));

    setCurrentFile("");
	
	connect(findWidget->findButton, SIGNAL(clicked()), this, SLOT(findCurrStr()));
    connect(findWidget->findStr, SIGNAL(returnPressed()), this, SLOT(findCurrStr()));
    connect(findWidget, SIGNAL(findClose()), this, SLOT(clearPaintTab()));
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (maybeSave()) {
        event->accept();
		findWidget->close();
    } else {
        event->ignore();
    }
}

void MainWindow::newFile()
{
    if (maybeSave()) {
        textEdit->clear();
        setCurrentFile("");
    }
}

void MainWindow::open()
{
    if (maybeSave()) {
        QString fileName = QFileDialog::getOpenFileName(this);
        if (!fileName.isEmpty())
            loadFile(fileName);
    }
}

bool MainWindow::save()
{
    if (getCurrentFile().isEmpty()) {
        return saveAs();
    } else {
        return saveFile(getCurrentFile());
    }
}

bool MainWindow::saveAs()
{
    QString fileName = QFileDialog::getSaveFileName(this);
    if (fileName.isEmpty())
        return false;

    return saveFile(fileName);
}

void MainWindow::find()
{
    findWidget->show();
}

void MainWindow::build()
{
    if (maybeSaveBeforeBuild())
    {
        if (!getCurrentFile().isEmpty())
            buildFile(getCurrentFile());
        tabWidget->setCurrentWidget(treeWidget);
    }
}

void MainWindow::about()
{
   QMessageBox::about(this, tr("About Application"),
            tr("The <b>Application</b> is Visual Parser for Makefiles."));
}

void MainWindow::documentWasModified()
{
    setWindowModified(textEdit->document()->isModified());
    buildAct->setEnabled(textEdit->document()->isModified());
    saveAct->setEnabled(textEdit->document()->isModified());
}

// Create and discribe actions
void MainWindow::createActions()
{
    newAct = new QAction(QIcon("i-make-files/image/newFile.png"), tr("New..."), this);
    newAct->setShortcuts(QKeySequence::New);
    newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

    openAct = new QAction(QIcon("i-make-files/image/openFile.png"), tr("Open..."), this);
    openAct->setShortcuts(QKeySequence::Open);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

    saveAct = new QAction(QIcon("i-make-files/image/saveFile.png"), tr("Save"), this);
    saveAct->setShortcuts(QKeySequence::Save);
    saveAct->setStatusTip(tr("Save the document to disk"));
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
    saveAct->setEnabled(false);

    saveAsAct = new QAction(tr("Save As..."), this);
    saveAsAct->setShortcuts(QKeySequence::SaveAs);
    saveAsAct->setStatusTip(tr("Save the document under a new name"));
    connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));

    exitAct = new QAction(tr("Exit"), this);
    exitAct->setShortcuts(QKeySequence::Quit);
    exitAct->setStatusTip(tr("Exit the application"));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

    buildAct = new QAction(QIcon("i-make-files/image/build.png"), tr("Build"), this);
    buildAct->setShortcuts(QKeySequence::Refresh);
    buildAct->setStatusTip(tr("Build tree of Makefile"));
    connect(buildAct, SIGNAL(triggered()), this, SLOT(build()));
    buildAct->setEnabled(false);

    undoAct = new QAction(QIcon("i-make-files/image/undo.png"), tr("Undo"), this);
    undoAct->setShortcuts(QKeySequence::Undo);
    undoAct->setStatusTip(tr("Undo"));
    connect(undoAct, SIGNAL(triggered()), textEdit, SLOT(undo()));
    undoAct->setEnabled(false);
    connect(textEdit, SIGNAL(undoAvailable(bool)), undoAct, SLOT(setEnabled(bool)));

    redoAct = new QAction(QIcon("i-make-files/image/redo.png"), tr("Redo"), this);
    redoAct->setShortcuts(QKeySequence::Redo);
    redoAct->setStatusTip(tr("Redo"));
    connect(redoAct, SIGNAL(triggered()), textEdit, SLOT(redo()));
    redoAct->setEnabled(false);
    connect(textEdit, SIGNAL(redoAvailable(bool)), redoAct, SLOT(setEnabled(bool)));

    cutAct = new QAction(QIcon("i-make-files/image/cut.png"), tr("Cut"), this);
    cutAct->setShortcuts(QKeySequence::Cut);
    cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
    connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
    cutAct->setEnabled(false);
    connect(textEdit, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));

    copyAct = new QAction(QIcon("i-make-files/image/copy.png"), tr("Copy"), this);
    copyAct->setShortcuts(QKeySequence::Copy);
    copyAct->setStatusTip(tr("Copy the current selection's contents to the clipboard"));
    connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
    copyAct->setEnabled(false);
    connect(textEdit, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));

    pasteAct = new QAction(QIcon("i-make-files/image/paste.png"), tr("Paste"), this);
    pasteAct->setShortcuts(QKeySequence::Paste);
    pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current selection"));
    connect(pasteAct, SIGNAL(triggered()), textEdit, SLOT(paste()));

    findAct = new QAction(QIcon("i-make-files/image/find.png"), tr("Find"), this);
    findAct->setShortcuts(QKeySequence::Find);
    findAct->setStatusTip(tr("Find"));
    connect(findAct, SIGNAL(triggered()), this, SLOT(find()));

    aboutAct = new QAction(tr("About"), this);
    aboutAct->setStatusTip(tr("Show the application's About box"));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
}

// Create and discribe menus
void MainWindow::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("File"));
    fileMenu->addAction(newAct);
    fileMenu->addAction(openAct);
    fileMenu->addAction(saveAct);
    fileMenu->addAction(saveAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    editMenu = menuBar()->addMenu(tr("Edit"));
    editMenu->addAction(undoAct);
    editMenu->addAction(redoAct);
    editMenu->addSeparator();
    editMenu->addAction(cutAct);
    editMenu->addAction(copyAct);
    editMenu->addAction(pasteAct);
	editMenu->addSeparator();
    editMenu->addAction(findAct);

    buildMenu = menuBar()->addMenu(tr("Build"));
    buildMenu->addAction(buildAct);

    menuBar()->addSeparator();

    helpMenu = menuBar()->addMenu(tr("Help"));
    helpMenu->addAction(aboutAct);
}

// Create and discribe tool bars
void MainWindow::createToolBars()
{
    fileToolBar = addToolBar(tr("File"));
    fileToolBar->addAction(newAct);
    fileToolBar->addAction(openAct);
    fileToolBar->addAction(saveAct);

    editToolBar = addToolBar(tr("Edit"));
    editToolBar->addAction(undoAct);
    editToolBar->addAction(redoAct);
    editToolBar->addSeparator();
    editToolBar->addAction(cutAct);
    editToolBar->addAction(copyAct);
    editToolBar->addAction(pasteAct);
    editToolBar->addSeparator();
    editToolBar->addAction(findAct);

    buildToolBar = addToolBar(tr("Build"));
    buildToolBar->addAction(buildAct);
}

// Create and discribe status bar
void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

bool MainWindow::maybeSaveBeforeBuild()
{
    if (textEdit->document()->isModified())
    {
        QMessageBox::StandardButton mes;
        mes = QMessageBox::warning(this, tr("Application"),
                                   tr("The document has been modified.\nDo you want to save your changes and build makefile?"),
                                   QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
        if (mes == QMessageBox::Yes)
            return save();
        else if (mes == QMessageBox::Cancel || mes == QMessageBox::No)
            return false;
    }
    return true;
}

bool MainWindow::maybeSave()
{
    if (textEdit->document()->isModified())
    {
        QMessageBox::StandardButton mes;
        mes = QMessageBox::warning(this, tr("Application"),
                                   tr("The document has been modified.\nDo you want to save your changes?"),
                                   QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
        if (mes == QMessageBox::Yes)
            return save();
        else if (mes == QMessageBox::Cancel)
            return false;
    }
    return true;
}

bool MainWindow::saveFile(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text))
    {
        QMessageBox::warning(this, tr("Application"), tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
        return false;
    }

    QTextStream out(&file);
    out << textEdit->toPlainText();

    setCurrentFile(fileName);
    saveAct->setEnabled(false);
    statusBar()->showMessage(tr("File saved"), 2000);
    return true;
}

void MainWindow::loadFile(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("Application"),
                             tr("Cannot read file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return;
    }

    // Sourse text
    QTextStream in(&file);
    QString strView = in.readAll();
    QString str = imake::readMakefile(fileName);
    textEdit->setPlainText(strView);

    // Tree
    imake::MakeInfo mi;
    imake::clearRootTargets(mi.rootTargets);
    imake::createTree(str, mi);
    imake::printAll_1(mi.rootTargets, treeWidget);

    // Variables
    imake::printVar(mi.vars, tableWidgetVar);

    // Special targets
    imake::printVar(mi.specialTargets, tableWidgetTarget);

    setCurrentFile(fileName);
    saveAct->setEnabled(false);
    buildAct->setEnabled(false);
    statusBar()->showMessage(tr("File loaded"), 2000);
}

void MainWindow::buildFile(const QString &fileName)
{

    // Исходный текст файла
    QString str = imake::readMakefile(fileName);

    // Дерево
    imake::MakeInfo mi;
    imake::clearRootTargets(mi.rootTargets);
    imake::createTree(str, mi);
    imake::printAll_1(mi.rootTargets, treeWidget);

    // Variables
    imake::printVar(mi.vars, tableWidgetVar);

    // Special targets
    imake::printVar(mi.specialTargets, tableWidgetTarget);

    saveAct->setEnabled(false);
    buildAct->setEnabled(false);
    statusBar()->showMessage(tr("File builded"), 2000);
}

void MainWindow::setCurrentFile(const QString &fileName)
{
    curFile = fileName;
    textEdit->document()->setModified(false);
    setWindowModified(false);

    QString shownName = curFile;
    if (curFile.isEmpty())
        shownName = "untitled";
    setWindowFilePath(shownName);
}

QString MainWindow::getCurrentFile()
{
    return curFile;
}

// Find in all tabs
void MainWindow::findCurrStr()
{
    clearPaintTab();

    findWidget->currStr = findWidget->findStr->text();

    if (findWidget->currStr.count() == 0)
        return;
    //findInTab(textEdit);
    findInTab(treeWidget);
    findInTab(tableWidgetVar);
    findInTab(tableWidgetTarget);
}

// Clear paint in all tabs
void MainWindow::clearPaintTab()
{
    //clearInTab(textEdit);
    clearInTab(treeWidget);
    clearInTab(tableWidgetVar);
    clearInTab(tableWidgetTarget);
}

// Find substring and paint in QTextEdit
void MainWindow::findInTab (QTextEdit *text)
{
    // Find the find string in document and paint
    text->moveCursor(QTextCursor::End);
        while (text->find(findWidget->currStr, QTextDocument::FindBackward))
            text->setTextBackgroundColor(Qt::yellow);
}

// Find substring and paint in QTreeWidget
void MainWindow::findInTab (QTreeWidget *tree)
{
    // Find node
    QList<QTreeWidgetItem *> *findList = new QList<QTreeWidgetItem *>;
    if (tree->topLevelItemCount() > 0)
        for(int i = 0; i < tree->topLevelItemCount(); i++)
        {
            QString nodeStr = tree->topLevelItem(i)->text(0);
            if (nodeStr.contains(findWidget->currStr, Qt::CaseInsensitive))
                findList->append(tree->topLevelItem(i));
            findInTree(tree->topLevelItem(i), findList);  // Recursion
        }

    // Paint and Open way
    QList<QTreeWidgetItem *>::iterator it = findList->begin();
    for ( ; it != findList->end(); ++it)
    {
        // Paint
        (*it)->setBackground(0, Qt::yellow);
        // Open way
        QTreeWidgetItem * currItem = *it;
        while (currItem != NULL)
        {
            tree->expandItem(currItem);
            currItem = currItem->parent();
        }
    }
}

// Recurse round of tree with find substring
void  MainWindow::findInTree(QTreeWidgetItem* item, QList<QTreeWidgetItem *> *findList)
{
    if (item == 0 ) return;

    QString nodeStr = item->text(0);
    if (nodeStr.contains(findWidget->currStr, Qt::CaseInsensitive))
        findList->append(item);

    if (item->childCount() > 0)
        for (int i = 0; i < item->childCount(); i++)
            if (item->child(i)!=0)
                findInTree(item->child(i), findList); // Recursion
}

// Find substring and paint in QTableWidget
void MainWindow::findInTab (QTableWidget *table)
{
    // Find node
    QList<QTableWidgetItem *> *findList = new QList<QTableWidgetItem *>;
    for (int i = 0; i < table->rowCount(); i++)
        for (int j = 0; j < table->columnCount(); j++)
        {
            QString nodeStr = table->item(i,j)->text();
            if (nodeStr.contains(findWidget->currStr, Qt::CaseInsensitive))
                findList->append(table->item(i,j));
        }

    // Paint
    QList<QTableWidgetItem *>::iterator it = findList->begin();
    for ( ; it != findList->end(); ++it) {
        (*it)->setBackground(Qt::yellow);
    }
}

// Clear paint in QTextEdit
void MainWindow::clearInTab (QTextEdit *text)
{
    // Keep text add set Background color
    text->moveCursor(QTextCursor::End);
    text->moveCursor(QTextCursor::Start, QTextCursor::KeepAnchor);
    text->setTextBackgroundColor(Qt::white);

    // Move cursor to start of document
    text->moveCursor(QTextCursor::Start);
}

// Clear paint in QTreeWidget
void MainWindow::clearInTab (QTreeWidget *tree)
{
    if (tree->topLevelItemCount() > 0)
        for(int i = 0; i < tree->topLevelItemCount(); i++)
        {
            tree->collapseItem(tree->topLevelItem(i));
            tree->topLevelItem(i)->setBackground(0, *brush);
            clearInTree(tree->topLevelItem(i), tree);  // Recursion
        }
}

// Recurse round of tree with clear paint
void  MainWindow::clearInTree(QTreeWidgetItem* item, QTreeWidget *tree)
{
    if (item == 0 ) return;
    tree->collapseItem(item);
    item->setBackground(0, *brush);
    if (item->childCount() > 0)
        for (int i = 0; i < item->childCount(); i++)
            if (item->child(i)!=0)
                clearInTree(item->child(i), tree); // Recursion
}

// Clear paint in QTableWidget
void MainWindow::clearInTab (QTableWidget *table)
{
    // Set background color in all items
    for (int i = 0; i < table->rowCount(); i++)
        for (int j = 0; j < table->columnCount(); j++)
            table->item(i,j)->setBackground(*brush);
}
